Docker Kata 6: Creating Docker Images
Learn to create an image from a modified container and with Dockerfile.
The previous katas have used images provided on Docker Hub. Most of those images are created and managed by software vendors.
This kata will demonstrate how we can define and build our own images for our own use or to distribute to others. This kata will cover two ways to create an image:
- Commit changes to a modified container.
- Build an image from a Dockerfile.
Step 1: Create an image from a modified container#
First, stop and remove all the containers and create an image from a modified container.
The output will be something like this:
Commands
Parameter/Command | Description |
| This creates, and then changes to, a new directory called |
| This copies the |
| This lists the files in the |
These commands create a new directory called dockerimage and copy a sample index.html file into that directory.
The command to run a disconnected NGINX container is given below.
If we run the command above, the output will be something like this:
Commands
Parameter | Description |
| This is the parent command. |
| This runs a container. |
| This assigns a name to a container. |
| This is the name to assign to the container. |
| This runs a container in disconnected mode. |
| This publishes a port from the container to the host. |
| This publishes port 80 on the container to port 80 on the host. |
| This is the name of the image to run. |
This command starts an NGNIX container using the same command from Kata 4.
The command to copy a file into the container is given below.
After execution of the command above, the result will be something like this:
Commands
Parameter | Description |
| This is the parent command. |
| The |
| This is the name of the file to copy into the container. |
| This is the image and the path. The name of the container to which the file should be copied is before the colon. The path inside the container to which the file should be copied follows the colon. The effect is that the |
The cp command copies files between containers and their hosts. This step copied the index.html file from the host to the container.
The command to open the NGINX server page is given below.
The result will be something like this:
The default NGINX welcome HTML we’ve seen previously has been replaced with the DevOps Katas custom page.
The curl command issues a request to the local system via HTTP. We can also use Firefox to view this page. Note that the welcome page has been modified. The index.html file copied in the previous step overwrote the default NGINX welcome page.
The command to list all the running containers is provided below.
The result of the command above will be something like this:
Commands
Parameter | Description |
| This is the parent command. |
| This lists the running containers when combined with the |
This step lists all the running containers. The NGINX container we ran in an earlier step is running.
The command to create an image from the container is given below.
The output will be something like this:
Commands
Parameter | Description |
| This is the parent command. |
| The |
| This is the name of the container from which to derive a new image. |
| This is the name assigned to the new image. |
The commit command is used to commit the changes to a container, thus creating a new image.
Recall in Kata 3 when we learned about file system changes in a container. When we copied the index.html file from the host to the NGINX container, we modified the container, but not the image from which that container was started. The commit command creates a new image called kataimage_nginx that includes that change.
The command to list all the images is given below.
When we run the command above, the result displayed will be something like:
Commands
Parameter | Description |
| This is the parent command. |
| This lists images when combined with the |
This command lists all the images. The kataimage_nginx image we created previously should be listed.
The command to run a disconnected container is given below.
After running the command above, the output will be something like this:
Commands
Parameter | Description |
| This is the parent command. |
| This runs a new container. |
| This runs a container in disconnected mode. |
| This publishes a container port to a host port. |
| This publishes container port 80 to host port 81. |
| This is the name of the image to run. |
This command runs a second NGINX container, this time using the kataimage_nginx image we created in the previous step.
The command to view the page of the container is given below.
The output of the command above will be something like this:
The curl command issues a request to the local system via HTTP. Note that the welcome page is the customized DevOps katas welcome page. The kataimage_nginx image includes the modified index.html file.
Step 2: Create an Image with a Dockerfile#
First, stop and remove all the containers.
The command to create a file is given below:
Enter (or copy/paste) the following text into the editor:
FROM nginx
ADD index.html /usr/share/nginx/html/index.html
RUN chmod 644 /usr/share/nginx/html/index.html
The output will be something like:
Commands
Parameter/Command | Description |
| The |
| The first line in the Dockerfile is always |
| The |
| The |
This step demonstrates the second method to create Docker images: a Dockerfile. The result is the same as the previous step; however, the commit method is an imperative method for creating images. That’s good for experimentation and testing, but a declarative method is better for building containers as part of a software delivery process.
A Dockerfile uses a declarative syntax to describe the contents of a container:
-The FROM part indicates the base image from which to create a new image. Any existing image may be used as the basis for any new image (except scratch, which is a non-runnable image used as a “bare-bones” base image). This step uses the NGINX image as its base image. The build process starts a temporary container from the base image defined in the FROM directive, then executes the following directives, creating the image.
The ADD command adds a file to the image. The source can be a file on the local file system or a URL to a file on the web. This step adds the custom index.html file (the same file as the one in the previous step) to the image.
The RUN entries execute commands within the image as it’s built. This command updates the permissions on the index.html file, which allows the NGINX HTTP server to read the file.
This Dockerfile builds a new image from the NGINX image. That image is available on Docker Hub. Let’s look at the Dockerfile for the official NGINX image to learn more about how Dockerfiles work.
Here’s the Dockerfile for the official NGINX image (current at the time of this writing):
FROM debian:jessie
MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com"
ENV NGINX_VERSION 1.11.10-1~jessie
RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys > 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \
&& echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> > /etc/apt/sources.list \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y \
ca-certificates \
nginx=${NGINX_VERSION} \
nginx-module-xslt \
nginx-module-geoip \
nginx-module-image-filter \
nginx-module-perl \
nginx-module-njs \
gettext-base \
&& rm -rf /var/lib/apt/lists/*
# forward request and error logs to Docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
This Dockerfile includes some of the same directives that are in the Dockerfile for kataimage_nginx and some that aren’t.
The FROM directive indicates the base image of the official NGINX image. The official NGINX image is based on the Jessie version of the official Debian Linux container. Public and official images are typically layered in this fashion. Base images start at the bottom or first layer with official OS distributions. Additional layers add software to the base image, creating a specialized container made for a specific purpose, such as a web server.
The MAINTAINER directive is deprecated in the current version of Docker. It has been replaced by the AUTHOR directive, which includes contact information for the creator of the Dockerfile.
The ENV directive sets the environment variables in the target image.
The following RUN command combines multiple installations and file system changes in a single command. The double ampersand (&&) may be used in Linux to execute multiple commands in one line. This technique is important when defining an image.
Docker uses a specialized layered file system to define images. When an image is created using FROM, a new layer is added to the file system that defines the image. The new top layer represents all the differences (installed programs, added files) between the base image and the new image. This layering system keeps images small by storing only the differences between the layers. Keeping images as small as possible makes image deployment faster and reduces storage space requirements for images and containers.
Each RUN command creates a new file system layer. If each of the commands in the NGINX Dockerfile were run separately, a new layer would be created for each execution. This would create many new layers, resulting in a larger image. Running all the commands in a single execution creates just one new layer.
The EXPOSE directive indicates to Docker that the container will listen on the port numbers specified. This isn’t the same as publishing the ports. The -p parameter is still necessary when running a container. It’s possible to use the -P (capital “P”) parameter to publish all the ports identified with EXPOSE. The -P parameter will publish all the exposed ports to the same port on the host. Given this NGINX Dockerfile, these two commands have the same effect:
docker container run -d -p 80:80 -p 443:443 nginx
docker container run -d -P nginx
The last directive in the NGINX Dockerfile is CMD:
CMD ["nginx", "-g", "daemon off;"]
There can only be one CMD directive in a Dockerfile (if there is more than one, the last one defined is the only one that will run).
The CMD directive is one of the methods to define the start command of the container. This method defines the program to run and its parameters:
CMD ["nginx", "-g", "daemon off;"]
Commands
Parameter/Command | Description |
| This is the NGINX HTTP server program. |
| This indicates that the following parameters are global configuration directives. This changes the configuration for this execution of the NGINX server. |
| This configures the NGINX server process to run in the foreground as the primary process, as opposed to running in the background as a service. This is recommended for running NGINX in a container. |
The command to build the image using Dockerfile is given below.
The result of the command above will be something like this:
Commands
Parameter | Description |
| This is the parent command. |
| This builds a new image from a Dockerfile when combined with the Docker image parent command. |
| This assigns a name, and if desired, a tag to the new image. |
| This is the name of the new image. The period after the name indicates the path to the Dockerfile. In Linux, a single period indicates the current directory. |
The build subcommand creates a new Docker image from a Dockerfile.
The command to list all the images is given below.
The result will be something like this:
Commands
Parameter | Description |
| This is the parent command. |
| This lists the images when combined with the |
This command lists all the images. The katadockerfile_image image should be listed.
The command to run a disconnected container is given below.
When we execute the command above, the output will be something like this:
Commands
Parameter | Description |
| This is the parent command. |
| This runs a container. |
| This runs a container in disconnected mode. |
| This publishes a container port to a host port. |
| This publishes container port 80 to host port 80. |
| This is the name of the image to run. |
This command runs the image that was created in the previous step using docker image build.
The command to view the page in the container is given below.
The output will be something like this:
This command returns the response from the NGINX container using curl. As expected, the result is the same as the previous kata step. This method, however, uses a declarative method. The Dockerfile used to create this image can be added to source control and used as part of an automated build process.
Practice commands#
We’ve given a terminal and table containing a list of commands discussed in this lesson. Try out these commands after running the terminal, and check out the results!
Commands
Step | Command |
This creates a |
|
This changes to the |
|
This copies the |
|
This lists the files in `dockerimage`. |
|
Run a disconnected NGINX container named |
|
This copies the |
|
This opens the NGINX server page using |
|
This lists all the running containers. |
|
This creates an image from the |
|
This lists all the images. |
|
This runs a disconnected container from |
|
This views the page of the |
|
This stops and removes all the containers. |
|
This creates a file called |
|
This enters the |
|
This builds the image using the |
|
This lists all the images. |
|
This runs a disconnected container from |
|
This views the page in the |
|
Docker Kata 5: Docker Networking
Quiz Yourself on Docker Commands